package com.hanxiaozhang.system.service.impl;

import com.hanxiaozhang.constant.CacheName;
import com.hanxiaozhang.constant.DelFlagEnum;
import com.hanxiaozhang.redis.util.CacheUtil;
import com.hanxiaozhang.result.Result;
import com.hanxiaozhang.security.CurrentUserUtil;
import com.hanxiaozhang.system.dao.*;
import com.hanxiaozhang.system.dto.CurrentUserDTO;
import com.hanxiaozhang.system.dto.UserDTO;
import com.hanxiaozhang.system.entity.*;
import com.hanxiaozhang.util.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.hanxiaozhang.system.service.UserService;
import org.springframework.transaction.annotation.Transactional;


/**
 * 用户表
 *
 * @author hanxiaozhang
 * @email hanxiaozhang2018@sina.com
 * @date 2021-04-02
 */
@Service
@CacheConfig(cacheNames = CacheName.CURRENT_USER_BY_USER_ID_2HOUR)
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;
    @Resource
    private DeptDao deptDao;
    @Resource
    private JobDao jobDao;
    @Resource
    private RoleDao roleDao;
    @Resource
    private UserDeptDao userDeptDao;
    @Resource
    private UserJobDao userJobDao;
    @Resource
    private UserRoleDao userRoleDao;
    @Autowired
    private CacheUtil cacheUtil;

    @Override
    public UserDTO get(Long userId) {
        return userDao.get(userId);
    }

    @Override
    @Cacheable(key = "#p0", unless = "#result == null")
    public CurrentUserDTO getCurrentUser(Long userId) {
        UserDTO user = userDao.get(userId);
        CurrentUserDTO currentUser = new CurrentUserDTO();
        BeanUtil.copyPropertiesIgnoreNull(user, currentUser);
        List<Long> deptIds = user.getDeptIds();
        if (!deptIds.isEmpty()) {
            currentUser.setDeptList(deptDao.listByDeptIds(deptIds));
        }
        List<Long> jobIds = user.getJobIds();
        if (!jobIds.isEmpty()) {
            currentUser.setJobList(jobDao.listByJobIds(jobIds));
        }
        List<Long> roleIds = user.getRoleIds();
        if (!roleIds.isEmpty()) {
            currentUser.setRoleList(roleDao.listByRoleIds(roleIds));
        }
        return currentUser;
    }

    @Override
    public List<UserDTO> list(Map<String, Object> map) {
        return userDao.list(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int save(UserDTO user) {

        String userName = CurrentUserUtil.getUserName();
        LocalDateTime now = LocalDateTime.now();
        List<Long> deptIds = user.getDeptIds();
        List<Long> jobIds = user.getJobIds();
        List<Long> roleIds = user.getRoleIds();
        user.setPassword(new BCryptPasswordEncoder().encode("12345678"))
                .setCreateBy(userName)
                .setCreateDate(now)
                .setDelFlag(DelFlagEnum.NORMAL.getCode());
        userDao.save(user);

        Long userId = user.getUserId();
        if (!deptIds.isEmpty()) {
            saveUserDept(deptIds, userId, userName, now);
        }
        if (!jobIds.isEmpty()) {
            saveUserJob(jobIds, userId, userName, now);
        }
        if (!roleIds.isEmpty()) {
            saveUserRole(roleIds, userId, userName, now);
        }

        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = {CacheName.CURRENT_USER_BY_USER_ID_2HOUR, CacheName.ROUTE_BY_USER_ID_2HOUR}, key = "#user.userId")
    public int update(UserDTO user) {

        List<Long> deptIds = user.getDeptIds();
        List<Long> jobIds = user.getJobIds();
        List<Long> roleIds = user.getRoleIds();
        String userName = CurrentUserUtil.getUserName();
        LocalDateTime now = LocalDateTime.now();
        Long userId = user.getUserId();
        if (!deptIds.isEmpty()) {
            userDeptDao.removeByUserId(userId);
            saveUserDept(deptIds, userId, userName, now);
        }
        if (!jobIds.isEmpty()) {
            userJobDao.removeByUserId(userId);
            saveUserJob(jobIds, userId, userName, now);
        }
        if (!roleIds.isEmpty()) {
            userRoleDao.removeByUserId(userId);
            saveUserRole(roleIds, userId, userName, now);
        }
        user.setUpdateBy(CurrentUserUtil.getUserName())
                .setUpdateDate(LocalDateTime.now());
        return userDao.update(user);
    }

    /**
     * 保存用户部门
     *
     * @param deptIds
     * @param userId
     * @param userName
     * @param now
     */
    private void saveUserDept(List<Long> deptIds, Long userId, String userName, LocalDateTime now) {

        List<UserDeptEntity> userDeptList = new ArrayList<>();
        deptIds.forEach(x -> {
            if (x == null) {
                return;
            }
            UserDeptEntity userDept = new UserDeptEntity();
            userDept.setDeptId(x)
                    .setUserId(userId)
                    .setCreateBy(userName)
                    .setCreateDate(now)
                    .setDelFlag(DelFlagEnum.NORMAL.getCode());
            userDeptList.add(userDept);
        });
        userDeptDao.batchSave(userDeptList);
    }

    /**
     * 保存用户岗位
     *
     * @param jobIds
     * @param userId
     * @param userName
     * @param now
     */
    private void saveUserJob(List<Long> jobIds, Long userId, String userName, LocalDateTime now) {

        List<UserJobEntity> userJobList = new ArrayList<>();
        jobIds.forEach(x -> {
            if (x == null) {
                return;
            }
            UserJobEntity userJob = new UserJobEntity();
            userJob.setJobId(x)
                    .setUserId(userId)
                    .setCreateBy(userName)
                    .setCreateDate(now)
                    .setDelFlag(DelFlagEnum.NORMAL.getCode());
            userJobList.add(userJob);
        });
        userJobDao.batchSave(userJobList);
    }


    /**
     * 保存用户角色
     *
     * @param roleIds
     * @param userId
     * @param userName
     * @param now
     */
    private void saveUserRole(List<Long> roleIds, Long userId, String userName, LocalDateTime now) {

        List<UserRoleEntity> userRoleList = new ArrayList<>();
        roleIds.forEach(x -> {
            if (x == null) {
                return;
            }
            UserRoleEntity userRole = new UserRoleEntity();
            userRole.setRoleId(x)
                    .setUserId(userId)
                    .setCreateBy(userName)
                    .setCreateDate(now)
                    .setDelFlag(DelFlagEnum.NORMAL.getCode());
            userRoleList.add(userRole);
        });
        userRoleDao.batchSave(userRoleList);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = {CacheName.CURRENT_USER_BY_USER_ID_2HOUR, CacheName.ROUTE_BY_USER_ID_2HOUR}, key = "#p0")
    public Result remove(Long userId) {
        if (userId.equals(CurrentUserUtil.getUserId())) {
            Result.error(10005, "不能删除自身用户");
        }
        userDeptDao.removeByUserId(userId);
        userJobDao.removeByUserId(userId);
        userRoleDao.removeByUserId(userId);
        userDao.remove(userId);
        return Result.success();
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result batchRemove(Long[] userIds) {
        for (Long userId : userIds) {
            if (userId.equals(CurrentUserUtil.getUserId())) {
                Result.error(10005, "不能删除自身用户");
            }
        }
        cacheUtil.delRouterAndCurUserByUserIds(userIds);
        userDeptDao.batchRemoveByUserIds(userIds);
        userJobDao.batchRemoveByUserIds(userIds);
        userRoleDao.batchRemoveByUserIds(userIds);
        userDao.batchRemove(userIds);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(UserDTO user) {
        Long userId = CurrentUserUtil.getUserId();
        String userName = CurrentUserUtil.getUserName();
        LocalDateTime now = LocalDateTime.now();
        user.setUserId(userId)
                .setUpdateBy(userName)
                .setUpdateDate(now);
        userDao.update(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePassword(Long userId, String passwordOne) {
        String userName = CurrentUserUtil.getUserName();
        LocalDateTime now = LocalDateTime.now();
        UserEntity user = new UserEntity();
        user.setUserId(userId)
                .setPassword(new BCryptPasswordEncoder().encode(passwordOne))
                .setUpdateBy(userName)
                .setUpdateDate(now);
        userDao.update(user);
    }


}
